#ifndef ASTNODE_H
#define ASTNODE_H

#define N_IF 		0
#define N_WHILE 	1
#define N_FOR 		2
#define N_FORDEF 	3
#define N_CONDITION 	4
#define N_ADD 		5
#define N_SUB 		6
#define N_MUL 		7
#define N_DIV 		8
#define N_AND 		9
#define N_OR 		10
#define N_NOT 		11
#define N_EXOR 		12
#define N_BAND 		13
#define N_BOR 		14
#define N_ASSIGN 	15
#define N_ASSIGNINDEX 	16
#define N_FUNCTION 	17
#define N_CALLER 	18


#include <vector>
#include <iostream>
#include <string>
#include "varlist.h"

using namespace std;


class Expression {
	public:
		virtual ~Expression () {}
		int etype;
		int rtype;
		Expression* Sibling;
		


		virtual void print()
		{	
			cout << " [ ";
		
			cout << "]" << endl;
		}

};

// For function
class Function : public Expression {
  

public:
	string name;
	Expression *statements;

	Function (string cname, int crtype)
	{
		etype = N_FUNCTION;
		name = cname;
		rtype = crtype;

	}
	Function (string cname, int crtype, Expression* cstatements)
	{
		etype = N_FUNCTION;
		name = cname;
		rtype = crtype;
		statements = cstatements;
	}

	// Copy constructor
	Function (const Function &other) 
	{
		etype = N_FUNCTION;
		name = other.name;
		rtype = other.rtype;
		statements = other.statements; /* clone yapcazz.. */
	}

	virtual ~Function () 
	{

	}

	Function &operator = (const Function &other) 
	{
		if (&other != this) {
			etype = N_FUNCTION;
			name = other.name;
			rtype = other.rtype;
			statements = other.statements; /* clone yapcazz.. */
		}
	}


  
};
// For additive expressions
class AssignVecVar : public Expression {
  

public:
   	Expression	*rhs;
	string 		lhs;

	AssignVecVar (string clhs, Expression* crhs)
	{
		lhs	 = clhs;
		rhs 	 = crhs;	
	}

	// Copy constructor
	AssignVecVar (const AssignVecVar &other) 
	{
		lhs	 = other.lhs;
		rhs 	 = other.rhs;	
	}

	virtual ~AssignVecVar () 
	{

	}

	AssignVecVar &operator = (const AssignVecVar &other) 
	{
		if (&other != this) {
			lhs	 = other.lhs;
			rhs 	 = other.rhs;	
		}
	}
	  


  
};

// For additive expressions
class AssignVar : public Expression {
  

public:
   	Expression	*rhs;
	string 		lhs;
	int 		index;

	AssignVar (string clhs, int cindex, Expression* crhs)
	{
		lhs	 = clhs;
		index	 = cindex;
		rhs 	 = crhs;	
	}

	// Copy constructor
	AssignVar (const AssignVar &other) 
	{
		lhs	 = other.lhs;
		index	 = other.index;
		rhs 	 = other.rhs;	
	}

	virtual ~AssignVar () 
	{

	}

	AssignVar &operator = (const AssignVar &other) 
	{
		if (&other != this) {
			lhs	 = other.lhs;
			index	 = other.index;
			rhs 	 = other.rhs;	
		}
	}
	  


  
};

// For additive expressions
class AddVar : public Expression {
  

public:
   	Expression *m_left, *m_right;

	AddVar (Expression *left, Expression *right): m_left (left), m_right (right) {}

	// Copy constructor
	AddVar (const AddVar &other) 
	{
		m_left = other.m_left;
		m_right = other.m_right;
	}

	virtual ~AddVar () 
	{
		delete m_left;
		delete m_right;
	}

	AddVar &operator = (const AddVar &other) 
	{
		if (&other != this) {
			delete m_left;
			delete m_right;

			m_left = other.m_left;
			m_right = other.m_right;
		}
	}
	  


  
};
// For subractive expressions
class SubtractVar : public Expression {
  

public:
   	Expression *m_left, *m_right;

	SubtractVar (Expression *left, Expression *right): m_left (left), m_right (right) {}

	// Copy constructor
	SubtractVar (const SubtractVar &other) 
	{
		m_left = other.m_left;
		m_right = other.m_right;
	}

	virtual ~SubtractVar () 
	{
		delete m_left;
		delete m_right;
	}

	SubtractVar &operator = (const SubtractVar &other) 
	{
		if (&other != this) {
			delete m_left;
			delete m_right;

			m_left = other.m_left;
			m_right = other.m_right;
		}
	}
	  

  
};
// For dividive expressions
class DivideVar : public Expression {
  

public:
   	Expression *m_left, *m_right;

	DivideVar (Expression *left, Expression *right): m_left (left), m_right (right) {}

	// Copy constructor
	DivideVar (const DivideVar &other) 
	{
		m_left = other.m_left;
		m_right = other.m_right;
	}

	virtual ~DivideVar () 
	{
		delete m_left;
		delete m_right;
	}

	DivideVar &operator = (const DivideVar &other) 
	{
		if (&other != this) {
			delete m_left;
			delete m_right;

			m_left = other.m_left;
			m_right = other.m_right;
		}
	}
	  
  
};
// For multiplicative expressions
class MultiplyVar : public Expression {
  

public:
   	Expression *m_left, *m_right;

	MultiplyVar (Expression *left, Expression *right): m_left (left), m_right (right) {}

	// Copy constructor
	MultiplyVar (const MultiplyVar &other) 
	{
		m_left = other.m_left;
		m_right = other.m_right;
	}

	virtual ~MultiplyVar () 
	{
		delete m_left;
		delete m_right;
	}

	MultiplyVar &operator = (const MultiplyVar &other) 
	{
		if (&other != this) {
			delete m_left;
			delete m_right;

			m_left = other.m_left;
			m_right = other.m_right;
		}
	}
	  

  
};

// For numbers
class ConstantVar : public Expression {
  
  
public:
	
	string name;
	int type;
	ConstantVar (string cname)
	{
		name = cname;
	}
	/*
	ConstantVar (string cname, int ctype, float start, float step, float end)
	{
		name = cname;
		type = ctype;
		if(type == 0)
		{		
			for(float i = start; i <= end; i+=step)
			{
				VarUType tmp;
				tmp.uint8 = (unsigned char)i;
				m_val.push_back(tmp);
			}		
		}	
		else if(type == 1)
		{		
			for(float i = start; i <= end; i+=step)
			{
				VarUType tmp;
				tmp.uint16 = (unsigned short)i;
				m_val.push_back(tmp);
			}		
		}
		else if(type == 2)
		{		
			for(float i = start; i <= end; i+=step)
			{
				VarUType tmp;
				tmp.uint32 = (unsigned int)i;
				m_val.push_back(tmp);
			}		
		}
		else if(type == 3)
		{		
			for(float i = start; i <= end; i+=step)
			{
				VarUType tmp;
				tmp.uint64 = (unsigned long)i;
				m_val.push_back(tmp);
			}		
		}
		else if(type == 4)
		{		
			for(float i = start; i <= end; i+=step)
			{
				VarUType tmp;
				tmp.int8 = (char)i;
				m_val.push_back(tmp);
			}		
		}
		else if(type == 5)
		{		
			for(float i = start; i <= end; i+=step)
			{
				VarUType tmp;
				tmp.int16 = (short)i;
				m_val.push_back(tmp);
			}		
		}
		else if(type == 6)
		{		
			for(float i = start; i <= end; i+=step)
			{
				VarUType tmp;
				tmp.int32 = (int)i;
				m_val.push_back(tmp);
			}		
		}
		else if(type == 7)
		{		
			for(float i = start; i <= end; i+=step)
			{
				VarUType tmp;
				tmp.int64 = (long)i;
				m_val.push_back(tmp);
			}		
		}
		else if(type == 8)
		{		
			for(float i = start; i <= end; i+=step)
			{
				VarUType tmp;
				tmp.float32 = i;
				m_val.push_back(tmp);
			}		
		}
	}
	*/
	// Copy constructor
	ConstantVar (const ConstantVar &other) 
	{ 
	
		name = other.name;
		type = other.type;
	}

	ConstantVar &operator = (const ConstantVar &other) 
	{
		if (&other != this)
		{

			name = other.name;
			type = other.type;
		}	
	}


};










class Program
{
	public:
	vector<Function*> AST;
	Function *dummy;
	string name;
	Program()
	{
		name = "firstever";
	}
	void containNode(Function *node)
	{
		AST.push_back(node);
	}
	void createTmpFunction()
	{
		dummy = new Function("tmp", 2);
		AST.push_back(dummy);
	}
	void listFunctions()
	{
		std::cout << "Functions:                                " << std::endl
			  << "------------------------------------------" << std::endl
			  << "id" << "\t" << "name" << "\t" << "rtype" << "\t" << "linecount" << std::endl;

		for(int i = 0; i < AST.size(); i++)
		{
			//std::cout << i << "\t" << AST[i]->name << "\t" << AST[i]->rtype << "\t" << AST[i]->Exp.size() << std::endl;
		}
			
	}	
	private:



};


#endif

